home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / ln03 / rose / dvi2ln3.lis < prev    next >
File List  |  1990-10-01  |  73KB  |  1,603 lines

  1.  
  2. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 1
  3. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  4.  
  5.  
  6.  
  7.     1            /* Dvi2ln3 translates a TeX DVI file to an LN03 format file. 
  8.     2             
  9.     3            Dvi2ln3 is still being developed. Copyright (c) 1985 by Digital Equipment
  10.     4            Corporation, Maynard, Massachusetts, USA. Author: Flavio Rose,
  11.     5            shasta!decwrl!dec-rhea!dec-dvinci!rose. 
  12.     6             
  13.     7            Dvi2ln3 is based on the publicly-available program DVItype, written by
  14.     8            David R. Fuchs of Stanford University; and also on earlier DEC programs for
  15.     9            the LN01 and LN03 laser printers, Dvi2lng, Topp and LN03Topp. This program
  16.    10            is not a DEC product and is not guaranteed to work. 
  17.    11             
  18.    12            Dvi2ln3 is written in VAX C. Specific VAX and VMS dependencies have
  19.    13            generally been avoided, however. The reader may find them by searching
  20.    14            for the strings VAX and VMS in this file.
  21.    15             
  22.    16            During development, double square brackets [[ ]] in a comment indicate some
  23.    17            places where the code needs to be improved. 
  24.    18             
  25.    19            [[Among the useful things that still need to be done: differentiating
  26.    20            between int and long variables so this can be ported more easily to 16-bit
  27.    21            architectures; testing to see if malloc returns 0; a \special for ROM
  28.    22            fonts; a \special for sixels.]] 
  29.    23             
  30.    24            Development history:
  31.    25             
  32.    26            Feb. 85:  Did some early work on Dvi2ln3, translating bits and pieces
  33.    27                      of Dvi2lng. Concluded, however, that it was better to translate
  34.    28                      LN03Topp and Dvi2lng into C first. The reason for this is that code 
  35.    29                      which mimics an existing program is easier to write and to test. 
  36.    30             
  37.    31            5/15/85:  At this date, the old LN03Topp program has been successfully
  38.    32                      translated into C (except for the ability to read files over
  39.    33                      DECnet). At this point, did some further cleanup of the Dvi2ln3 
  40.    34                      source. 
  41.    35             
  42.    36             6/4/85:  Coding of Dvi2ln3 begins in earnest. Merging bits and
  43.    37                      pieces from various places. Chucking chunks and all that
  44.    38                      junk from LN03Topp; pass2 is just straightforward translation.
  45.    39             
  46.    40            6/22/85:  Cleanup after initial debugging. Ready to distribute.
  47.    41             
  48.    42            10/14/85: Bug in parsing of \special's. Version 1.
  49.    43             
  50.    44            */ 
  51.    45             
  52.    46            #include stdio
  53.   104             
  54.   105            /* To please the VMS linker, we declare all global variables to be
  55.   106            globaldef. This is done with #define's, so it may easily be undone when
  56.  
  57. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 2
  58. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  59.  
  60.   107            porting the program to other systems. */ 
  61.   108             
  62.   109            #ifdef vms
  63.   110            #define GLOBAL globaldef
  64.   111            #define EXTERN globalref
  65.   112            #else
  66.   113   X        #define GLOBAL 
  67.   114   X        #define EXTERN extern
  68.   115            #endif
  69.   116             
  70.   117            /* hoff is the horizontal offset in pixels to be added to all dimensions
  71.   118            read in; voff is the corresponding vertical offset. */
  72.   119             
  73.   120            GLOBAL int hoff, voff, startp;
  74.   121            GLOBAL FILE *dvifile,*tfmfile,*outfile;
  75.   122             
  76.   123            /* Each page in a DVI file is identified by ten longwords, which appear
  77.   124            immediately after each bop (beginning of page) command. Dvi2ln3, like
  78.   125            DVItype, supports certain options that allow one to print only selected
  79.   126            pages. The following variables are used for this purpose. 
  80.   127             
  81.   128            Num_pages is a count of how many pages have been passed to the output.
  82.   129            Max_pages is the user-specified maximum number of pages to pass.
  83.   130            How_many_counts denotes the number of identifying longwords to take into
  84.   131            account when searching for the user-specified starting page. The user
  85.   132            specifies the starting page as the first one whose identifying longwords
  86.   133            match certain specified values, stored in start_page. However, identifying
  87.   134            longword i is only required to match the value in start_page[i] if
  88.   135            use_count[i] is nonzero. */ 
  89.   136             
  90.   137            GLOBAL long int num_pages,max_pages;
  91.   138            GLOBAL int how_many_counts,use_count[10];
  92.   139            GLOBAL long int start_page[10];
  93.   140             
  94.   141            /* FILESPECLEN is the maximum size of a file specification under VMS.
  95.   142            [[Perhaps arrays of fixed size should not be used, but rather malloc should
  96.   143            be employed...]] */ 
  97.   144             
  98.   145            #define FILESPECLEN 252
  99.   146             
  100.   147            /* The main routine deals with the command line arguments, opens the dvi
  101.   148            file, and then calls various other routines to handle the "passes". There
  102.   149            are two passes which involve reading the DVI file; in between, the font
  103.   150            load is constructed. */ 
  104.   151             
  105.   152            main(argc,argv) 
  106.   153            int argc;
  107.   154            char *argv[];
  108.   155            {
  109.   156    1           int status,i,jnam,jext;
  110.   157    1           char infnam[FILESPECLEN];
  111.  
  112. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 3
  113. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  114.  
  115.   158    1        
  116.   159    1           if (argc < 2) { printf("\n Usage: Dvi2ln3 <filename> <options>");
  117.   160    2               goto exit_label; }
  118.   161    1        
  119.   162    1           printf("\n Dvi2ln3 1");
  120.   163    1        
  121.   164    1           strcpy(infnam,argv[1]);
  122.   165    1        
  123.   166    1       /* The extension of the input file defaults to .dvi. Locate the filename
  124.   167    1       field within the filespec parameter, set jname to point to beginning, jext
  125.   168    1       to point to one place after end. [[This code is of course dependent on the
  126.   169    1       VMS filespec syntax.]] */ 
  127.   170    1        
  128.   171    1           find_VMS_filename(infnam,&jnam,&jext);
  129.   172    1           if (infnam[jext] == '\0') strcat(infnam,".dvi");
  130.   173    1           dvifile = fopen(infnam,"r");
  131.   174    1           if (dvifile == NULL) { printf("\n Couldn't open dvi file");
  132.   175    2               goto exit_label; }
  133.   176    1        
  134.   177    1       /* Now decipher the options off the command line. */
  135.   178    1        
  136.   179    1           max_pages = 1000000000;
  137.   180    1           how_many_counts = 0;
  138.   181    1           hoff = 300;
  139.   182    1           voff = 300;
  140.   183    1           for (i=2; i<argc; i++) command_line_options(argv[i]);
  141.   184    1        
  142.   185    1           status = pass1();
  143.   186    1           if (status != 0) goto exit_label; 
  144.   187    1           if (rewind(dvifile) == -1) {
  145.   188    2               printf("\n Couldn't rewind dvi file.");
  146.   189    2               goto exit_label;
  147.   190    2           }
  148.   191    1        
  149.   192    1           status = open_output_file(infnam,jnam,jext,".ln3");
  150.   193    1           if (status != 0) { printf("\n Couldn't open output file");
  151.   194    2               goto exit_label; }
  152.   195    1        
  153.   196    1           status = make_font_load();
  154.   197    1           if (status != 0) goto exit_label;
  155.   198    1        
  156.   199    1           pass2();
  157.   200    1        
  158.   201    1           fprintf(outfile,"\033c");
  159.   202    1           fclose(dvifile);
  160.   203    1           fclose(outfile);
  161.   204    1        
  162.   205    1       exit_label:
  163.   206    1           ;
  164.   207    1       }
  165.   208             
  166.  
  167. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 4
  168. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  169.  
  170.   209            /* Find_VMS_filename finds the filename part of a VMS filespec passed in s,
  171.   210            returning the index of the first character in *ns, and the index of the
  172.   211            character after the last in *ne. 
  173.   212             
  174.   213            [[When porting Dvi2ln3 to a non-VMS system, we need to find an alternative
  175.   214            to this function. Under Unix, as a first approximation, we could look for
  176.   215            the last "/" or "~" and then for the first succeeding "." in the filespec.
  177.   216            Is this correct?]] */ 
  178.   217             
  179.   218            int find_VMS_filename(s,ns,ne)
  180.   219            char s[];
  181.   220            int *ns,*ne;
  182.   221            {
  183.   222    1           int jnam,jext,j,slen;
  184.   223    1        
  185.   224    1           slen = strlen(s);
  186.   225    1           jnam = 0;
  187.   226    1           for (j = slen-1; j >= 0; j--) {
  188.   227    2               if (s[j] == ':' || s[j] == ']' ||
  189.   228    2                   s[j] == '>') {
  190.   229    3                   jnam = j+1;
  191.   230    3                   break;
  192.   231    3               }
  193.   232    2           }
  194.   233    1        
  195.   234    1           jext = slen;    
  196.   235    1           for (j = jnam; j < slen; j++) {
  197.   236    2               if (s[j] == '.' || s[j] == ';') {
  198.   237    3                   jext = j;
  199.   238    3                   break;
  200.   239    3               }
  201.   240    2           }
  202.   241    1        
  203.   242    1           *ns = jnam;
  204.   243    1           *ne = jext;
  205.   244    1       }
  206.   245             
  207.   246            /* ERROR HANDLING: Errors should be reported as close to the source as
  208.   247            possible, so that the maximum amount of information is available to the
  209.   248            user to identify the error. 
  210.   249             
  211.   250            Errors in the format of DVI or TFM files are not reported specifically,
  212.   251            since there exist programs, DVItype and TFtoPL, which diagnose errors in
  213.   252            such files. This program accepts some incorrect DVI files, for example,
  214.   253            those with a bad postamble or bad backpointers. [[However, someday we may
  215.   254            rewrite the program to select pages by using these features of the DVI
  216.   255            format, rather than by skipping unwanted pages.]] */ 
  217.   256             
  218.   257            GLOBAL char *bad_DVI_message = "\nBad DVI file - check it with DVItype";
  219.   258             
  220.   259            /* Command_line_options reads and processes options off the string s. At
  221.  
  222. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 5
  223. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  224.  
  225.   260            this time, four options are supported. 
  226.   261             
  227.   262            The N option sets the maximum number of pages to be printed. Its syntax is
  228.   263            /N=<integer> . 
  229.   264             
  230.   265            The H option modifies the default horizontal offset.
  231.   266             
  232.   267            The V option modifies the default vertical offset. 
  233.   268             
  234.   269            The S option has syntax /S=<pagespec>{.<pagespec>}* where the {}* denotes
  235.   270            repetition, and a <pagespec> is either an integer or * to indicate any
  236.   271            value. An example would be "/S=*.8.3". 
  237.   272             
  238.   273            The meaning of the S option is as follows: In a DVI file, pages are
  239.   274            identified by ten longword values which follow each bop (beginning of page)
  240.   275            command. The value of the S option indicates which page to start printing
  241.   276            on. For example, "*.8.3" means start printing at the first page whose
  242.   277            second identifying longword is 8 and third is 3. */
  243.   278             
  244.   279            int command_line_options(t)
  245.   280            char *t;
  246.   281            {
  247.   282    1           long int i,k;
  248.   283    1           char *u;
  249.   284    1        
  250.   285    1           while ((t = strchr(t,'/')) != 0) {
  251.   286    2           t++;
  252.   287    2               if (toupper(t[0]) == 'N' && t[1] == '=' 
  253.   288    2                   && (sscanf(&t[2],"%ld",&k) == 1)) 
  254.   289    2               max_pages = k;
  255.   290    2               if (toupper(t[0]) == 'H' && t[1] == '=' 
  256.   291    2                   && (sscanf(&t[2],"%ld",&k) == 1)) 
  257.   292    2               hoff = k;
  258.   293    2               if (toupper(t[0]) == 'V' && t[1] == '=' 
  259.   294    2                   && (sscanf(&t[2],"%ld",&k) == 1)) 
  260.   295    2               voff = k;
  261.   296    2               else if (toupper(t[0]) == 'S' && t[1] == '=') {
  262.   297    3               t += 2;
  263.   298    3               how_many_counts = 0;
  264.   299    3               for (;;) {
  265.   300    4                   if (t[0] == '*') {
  266.   301    5                   use_count[how_many_counts] = 0;
  267.   302    5                   how_many_counts++;
  268.   303    5               }
  269.   304    4               else if (sscanf(t,"%ld",&k) != 0) {
  270.   305    5                   use_count[how_many_counts] = 1;
  271.   306    5                   start_page[how_many_counts] = k;
  272.   307    5                   how_many_counts++;
  273.   308    5               } else break;
  274.   309    4                   u = strchr(t,'.');
  275.   310    4                   if (u == 0) break;
  276.  
  277. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 6
  278. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  279.  
  280.   311    4                   t = &u[1];
  281.   312    4               }
  282.   313    3           }
  283.   314    2           } 
  284.   315    1       }
  285.   316             
  286.   317            /* Open_output_file opens one of the output files, using the file pointer
  287.   318            outfile. The name of the output file is obtained by appending the string
  288.   319            ext to the substring of infnam beginning at jnam and ending at jext. 
  289.   320             
  290.   321            [[This code contains a VMS depndency. We use creat followed by fdopen to
  291.   322            open the file as a normal VMS file ("rat=cr","rfm=var") rather than a
  292.   323            STREAM_LF file. Beginning with VAX C V2.0, this can be done by just calling
  293.   324            fopen.]] */ 
  294.   325             
  295.   326            int open_output_file(infnam,jnam,jext,ext)
  296.   327            char *infnam,*ext;
  297.   328            int jnam,jext;
  298.   329            {
  299.   330    1           char outfnam[FILESPECLEN];
  300.   331    1           int jj;
  301.   332    1        
  302.   333    1           strcpy(outfnam,&infnam[jnam]);
  303.   334    1           strcpy(&outfnam[jext-jnam],ext);
  304.   335    1        
  305.   336    1           jj = creat(outfnam,0,"rat=cr","rfm=var");
  306.   337    1           if (jj == -1) return(1);
  307.   338    1           outfile = fdopen(jj,"w");
  308.   339    1           if (outfile == NULL) return(1);
  309.   340    1        
  310.   341    1           return(0);
  311.   342    1       }
  312.   343             
  313.   344            /* Bytes are read one by one from the DVI file using getc. We use an
  314.   345            overlay, as suggested in the DVItype documentation, to combine these bytes
  315.   346            into larger integers. [[Note that this technique relies on the fact that
  316.   347            numbers on the VAX are stored with the least significant byte first. The
  317.   348            macros below would have to be changed if the program were to be ported to a
  318.   349            machine architecture for which this is not so.]] 
  319.   350             
  320.   351            [[The use of getc is expensive, since getc is a function in VAX C V2.0.
  321.   352            Eventually, one would want to rewrite these macros to work like the old
  322.   353            getc macro.]] */ 
  323.   354             
  324.   355            GLOBAL union lc { long int l; unsigned long int ul; char c[4]; 
  325.   356                    unsigned char uc[4]; } lcx;
  326.   357             
  327.   358            #define two_bytes_u lcx.uc[1] = getc(dvifile); \
  328.   359                lcx.uc[0] = getc(dvifile); lcx.uc[2] = 0; lcx.uc[3] = 0
  329.   360             
  330.   361            #define two_bytes_s lcx.c[1] = getc(dvifile); \
  331.  
  332. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 7
  333. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  334.  
  335.   362                lcx.c[0] = getc(dvifile);  \
  336.   363                if (lcx.c[1] >= 0) { lcx.uc[2] = 0; lcx.uc[3] = 0 ;} \
  337.   364                else { lcx.uc[2] = 255; lcx.uc[3] = 255; }
  338.   365             
  339.   366            #define three_bytes_u lcx.uc[3] = getc(dvifile); lcx.uc[1] = getc(dvifile); \
  340.   367                lcx.uc[0] = getc(dvifile); lcx.uc[2] = 0
  341.   368             
  342.   369            #define three_bytes_s lcx.c[2] = getc(dvifile); lcx.c[1] = getc(dvifile); \
  343.   370                lcx.c[0] = getc(dvifile);  \
  344.   371                lcx.uc[3] = (lcx.c[2] >= 0) ? 0 : 255;
  345.   372             
  346.   373            #define four_bytes lcx.c[3] = getc(dvifile); \
  347.   374                lcx.c[2] = getc(dvifile); lcx.c[1] = getc(dvifile); \
  348.   375                lcx.c[0] = getc(dvifile); 
  349.   376             
  350.   377            /* Knuth's programs like to hardcode fixed maximum sizes for various
  351.   378            things, for example, the maximum number of fonts allowed in a DVI file. In
  352.   379            general, it is preferable to use the C function malloc to allocate storage
  353.   380            as needed. That is what we generally do in this Dvi2ln3, but there are some
  354.   381            residues of the Knuthian approach, like MAXTEXFONTS below. By the way, we
  355.   382            never attempt to return any storage to the system. 
  356.   383             
  357.   384            [[Eventually, it would be better to get rid of MAXTEXFONTS and use a linked
  358.   385            list of records instead. There would be no cpu time penalty to using a
  359.   386            linked list, because the function set_curf below does a linear search
  360.   387            through the font array anyway.]] */
  361.   388             
  362.   389            #define MAXTEXFONTS 100
  363.   390             
  364.   391            struct txf { unsigned char chu[256]; int bc, ec; long int space, design_size,
  365.   392                scaled_size; int nchs; };
  366.   393             
  367.   394            GLOBAL struct txf *txfa[MAXTEXFONTS+1];
  368.   395             
  369.   396            /* Font width information needs to be read from TFM files. TFM is a special
  370.   397            format defined by TeX. Dvi2ln3 stores each width in a longword. DVItype
  371.   398            tries to save space by a two-level width storage method. We just allocate
  372.   399            an array of widths for each font with malloc. 
  373.   400             
  374.   401            [[We don't check that font checksums match in Dvi2ln3, because there are a
  375.   402            lot of slightly obsolete TFMs floating around which would result in a
  376.   403            checksum error, but seem to give perfectly reasonable formatted output
  377.   404            nonetheless.]] */ 
  378.   405             
  379.   406            GLOBAL long int *font_width[MAXTEXFONTS+1];
  380.   407             
  381.   408            /* TeX fonts are referred to by their internal numbers, which go from 0 to
  382.   409            nf-1. The DVI file refers to them by external numbers, hence the array
  383.   410            to_ext used to convert internal numbers to external numbers. Curf is the
  384.   411            internal font number of the current font in the DVI file. */ 
  385.   412             
  386.  
  387. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 8
  388. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  389.  
  390.   413            GLOBAL int to_ext[MAXTEXFONTS+1],
  391.   414                nf,
  392.   415                curf;
  393.   416             
  394.   417            /* In some switch statements, a lot of cases have to be enumerated. We
  395.   418            employ this Knuthian macro for that purpose: */ 
  396.   419             
  397.   420            #define four_cases(_x1) case _x1: case _x1+1: case _x1+2: case _x1+3: 
  398.   421             
  399.   422            /* We define a lot of constants corresponding to the DVI operation codes.
  400.   423            These are copied from DVItype. */ 
  401.   424             
  402.   425            #define id_byte 2    /* current version of the dvi format */
  403.   426            #define set_char_0 0 /* typeset character 0 and move right */
  404.   427            #define set1 128     /* typeset a character and move right */
  405.   428            #define set_rule 132 /* typeset a rule and move right */
  406.   429            #define put1 133     /* typeset a character */
  407.   430            #define put_rule 137 /* typeset a rule */
  408.   431            #define nop 138      /* no operation */
  409.   432            #define bop 139      /* beginning of page */
  410.   433            #define eop 140      /* ending of page */
  411.   434            #define push 141     /* save the current positions */
  412.   435            #define pop 142      /* restore previous positions */
  413.   436            #define right1 143   /* move right */
  414.   437            #define w0 147       /* move right by |w| */
  415.   438            #define w1 148       /* move right and set |w| */
  416.   439            #define x0 152       /* move right by |x| */
  417.   440            #define x1 153       /* move right and set |x| */
  418.   441            #define down1 157    /* move down */
  419.   442            #define y0 161       /* move down by |y| */
  420.   443            #define y1 162       /* move down and set |y| */
  421.   444            #define z0 166       /* move down by |z| */
  422.   445            #define z1 167       /* move down and set |z| */
  423.   446            #define fnt_num_0 171 /* set current font to 0 */
  424.   447            #define fnt1 235     /* set current font */
  425.   448            #define xxx1 239     /* extension to dvi primitives (\special) */
  426.   449            #define xxx4 242     /* potentially long extension to dvi primitives */
  427.   450            #define fnt_def1 243 /* define the meaning of a font number */
  428.   451            #define pre 247      /* preamble */
  429.   452            #define post 248     /* postamble beginning */
  430.   453            #define post_post 249 /* postamble ending */
  431.   454            #define undefined_command 250
  432.   455             
  433.   456            GLOBAL long int mag, num, den;
  434.   457            GLOBAL float conv, unmag_conv;
  435.   458             
  436.   459            /* Read_preamble reads the preamble of the dvi file. The comment is thrown
  437.   460            away. The format version number is checked. The magnification, numerator,
  438.   461            and denominator are remembered in the globals mag, num, den. The float
  439.   462            values conv and unmag_conv serve to convert measurements from DVI units to
  440.   463            pixels. */ 
  441.  
  442. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 9
  443. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  444.  
  445.   464             
  446.   465            int read_preamble() {
  447.   466    1           unsigned int i;
  448.   467    1           int j;
  449.   468    1        
  450.   469    1           i = getc(dvifile);
  451.   470    1           if (i != pre) return(1);
  452.   471    1           i = getc(dvifile);
  453.   472    1           if (i != id_byte) return(1);
  454.   473    1           four_bytes; num = lcx.l;
  455.   474    1           if (num <= 0) return(1);
  456.   475    1           four_bytes; den = lcx.l;
  457.   476    1           if (den <= 0) return(1);
  458.   477    1           four_bytes; mag = lcx.l;
  459.   478    1           if (mag <= 0) return(1);
  460.   479    1        
  461.   480    1           unmag_conv = (num/254000.0) * (300.0/den);
  462.   481    1           conv = unmag_conv * (mag/1000.0);
  463.   482    1        
  464.   483    1       /* Skip over the comment field. */
  465.   484    1           
  466.   485    1           i = getc(dvifile);
  467.   486    1           for (j=0; j<i; j++) getc(dvifile);
  468.   487    1           return(0);
  469.   488    1       }
  470.   489             
  471.   490            /* The dvi file format requires us to keep track of various quantities,
  472.   491            among them the horizontal and vertical positions h and v, and four values
  473.   492            referred to simply as x, y, z and w. We also keep pixel-rounded versions
  474.   493            of h and v, called hh and vv. */ 
  475.   494             
  476.   495            GLOBAL long h, v, x, y, z, w;
  477.   496            GLOBAL int hh, vv;
  478.   497             
  479.   498            /* The following function, copied from DVItype, reads from the DVI file the
  480.   499            first parameter of the current DVI command. In the case of functions whose
  481.   500            first parameter is implicit, such as set_char_0 through set_char_127, the
  482.   501            implicit parameter is returned. */ 
  483.   502             
  484.   503            long first_par(o)
  485.   504            int o;
  486.   505            {
  487.   506    1           unsigned int i;
  488.   507    1        
  489.   508    1           if ((o >= set_char_0) && (o < set_char_0+128))
  490.   509    1           return(o-set_char_0);
  491.   510    1           if ((o >= fnt_num_0) && (o < fnt_num_0+64))
  492.   511    1               return(o-fnt_num_0);
  493.   512    1           switch (o) {
  494.   513    2               case set1:
  495.   514    2               case put1:
  496.  
  497. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 10
  498. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  499.  
  500.   515    2               case fnt1:
  501.   516    2               case xxx1:
  502.   517    2               case fnt_def1:
  503.   518    2                   i = getc(dvifile);
  504.   519    2               return(i);
  505.   520    2               case set1+1:
  506.   521    2               case put1+1:
  507.   522    2               case fnt1+1:
  508.   523    2               case xxx1+1:
  509.   524    2               case fnt_def1+1:
  510.   525    2                   two_bytes_u;
  511.   526    2               return(lcx.ul);
  512.   527    2               case set1+2:
  513.   528    2               case put1+2:
  514.   529    2               case fnt1+2:
  515.   530    2               case xxx1+2:
  516.   531    2               case fnt_def1+2:
  517.   532    2                   three_bytes_u;
  518.   533    2               return(lcx.ul);
  519.   534    2               case right1:
  520.   535    2               case w1:
  521.   536    2               case x1:
  522.   537    2               case down1:
  523.   538    2               case y1:
  524.   539    2               case z1:
  525.   540    2               return(getc(dvifile));
  526.   541    2               case right1+1:
  527.   542    2               case w1+1:
  528.   543    2               case x1+1:
  529.   544    2               case down1+1:
  530.   545    2               case y1+1:
  531.   546    2               case z1+1:
  532.   547    2                   two_bytes_s;
  533.   548    2               return(lcx.l);
  534.   549    2               case right1+2:
  535.   550    2               case w1+2:
  536.   551    2               case x1+2:
  537.   552    2               case down1+2:
  538.   553    2               case y1+2:
  539.   554    2               case z1+2:
  540.   555    2                   three_bytes_s;
  541.   556    2               return(lcx.l);
  542.   557    2               case set_rule:
  543.   558    2               case put_rule:
  544.   559    2               case right1+3:
  545.   560    2               case w1+3:
  546.   561    2               case x1+3:
  547.   562    2               case down1+3:
  548.   563    2               case y1+3:
  549.   564    2               case z1+3:
  550.   565    2               case set1+3:
  551.  
  552. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 11
  553. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  554.  
  555.   566    2               case put1+3:
  556.   567    2               case fnt1+3:
  557.   568    2               case xxx1+3:
  558.   569    2               case fnt_def1+3:
  559.   570    2                   four_bytes;
  560.   571    2                   return(lcx.l);
  561.   572    2           case w0:
  562.   573    2               return(w);
  563.   574    2           case x0:
  564.   575    2               return(x);
  565.   576    2           case y0:
  566.   577    2               return(y);
  567.   578    2           case z0:
  568.   579    2               return(z);
  569.   580    2           default:
  570.   581    2               return(0);
  571.   582    2           }
  572.   583    1       }
  573.   584             
  574.   585            /* Pass1 reads from the DVI file until the starting page condition is met.
  575.   586            Return 1 if something goes wrong, or if the DVI file comes to an end. This
  576.   587            resembles skip_pages below. */ 
  577.   588             
  578.   589            int pass1() {
  579.   590    1        
  580.   591    1           unsigned int k;
  581.   592    1           long int p;
  582.   593    1           int i;
  583.   594    1           char startp;
  584.   595    1           
  585.   596    1           if (read_preamble() != 0) {
  586.   597    2               printf(bad_DVI_message);
  587.   598    2               return(1);
  588.   599    2           }
  589.   600    1        
  590.   601    1           for (;;) {
  591.   602    2           if (feof(dvifile)) {
  592.   603    3               printf(bad_DVI_message);
  593.   604    3               return(1);
  594.   605    3           }
  595.   606    2           k = getc(dvifile);
  596.   607    2           if (k == post) return(0);
  597.   608    2           p = first_par(k);
  598.   609    2           if (k >= set_char_0 && k < set_char_0+128) k = set1;
  599.   610    2           if (k >= fnt_num_0 && k < fnt_num_0+64) k = fnt1;
  600.   611    2        
  601.   612    2           switch (k) {
  602.   613    3               case bop:
  603.   614    3               startp = 1;
  604.   615    3               for (i=0; i<10; i++) {
  605.   616    4                   four_bytes;
  606.  
  607. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 12
  608. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  609.  
  610.   617    4                   if (i < how_many_counts && use_count[i] &&
  611.   618    4                       lcx.l != start_page[i]) startp = 0;
  612.   619    4                   }
  613.   620    3                   four_bytes;
  614.   621    3               if (startp != 0) num_pages = 1;
  615.   622    3                   else if (num_pages > 0) {
  616.   623    4                   num_pages++;
  617.   624    4                   if (num_pages > max_pages) return(0);
  618.   625    4               }
  619.   626    3                   break;
  620.   627    3                   case set_rule:
  621.   628    3                   case put_rule:
  622.   629    3                   four_bytes;
  623.   630    3                   break;
  624.   631    3               four_cases(fnt_def1)
  625.   632    3                   i = define_font(p);
  626.   633    3                   if (i != 0) return(1);
  627.   634    3                   break;
  628.   635    3               four_cases(fnt1)
  629.   636    3               if (num_pages > 0) set_curf(p);
  630.   637    3               break;
  631.   638    3                   four_cases(set1)
  632.   639    3               four_cases(put1)
  633.   640    3                   if (num_pages > 0)
  634.   641    3                   txfa[curf] -> chu[p] = 1;
  635.   642    3               break;
  636.   643    3               four_cases(xxx1)
  637.   644    3                   for (; p>0; p--) getc(dvifile);
  638.   645    3               break;
  639.   646    3                   default:
  640.   647    3                   break;
  641.   648    3           }
  642.   649    2           }
  643.   650    1           return(0);
  644.   651    1       }
  645.   652             
  646.   653            #define leftfirst 33
  647.   654            #define rightfirst 161
  648.   655            #define leftlast 126
  649.   656            #define rightlast 254
  650.   657             
  651.   658            /* The define of maxnfonts below is based on a belief, perhaps
  652.   659            superstitious, that there is a limit of 31 downline-loaded fonts in the
  653.   660            LN03. For us an nfont is two LN03 fonts, hence the following definition. */
  654.   661             
  655.   662            #define maxnfonts 16
  656.   663             
  657.   664            /* Txf is a record structure describing a TeX font. Txfa is an array of txf
  658.   665            records. Txf2lnf describes the mapping between TeX fonts and pairs of LN03
  659.   666            fonts. Because the constructed LN03 font load has just the glyphs that are
  660.   667            needed, we can often cram more than one TeX font into a pair of LN03 fonts.
  661.  
  662. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 13
  663. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  664.  
  665.   668             
  666.   669            Why a pair of fonts? Because LN03 fonts are allowed to hold 94 glyphs only.
  667.   670            They come in two flavors, "left" which answer to character codes 33 to 126,
  668.   671            and "right" which answer to codes 161 to 254. LN03Topp assigns each TeX
  669.   672            font to one "lnfno", where each lnfno denotes a pair of LN03 fonts, one
  670.   673            left, one right. */ 
  671.   674             
  672.   675            GLOBAL int txf2lnf[MAXTEXFONTS];
  673.   676             
  674.   677            /* Maxfontnos reflects the fact that all LN03 fonts must be denoted by
  675.   678            a number from 10 to 19. */
  676.   679             
  677.   680            #define maxfontnos 9
  678.   681             
  679.   682            GLOBAL int lastch[maxnfonts];
  680.   683            GLOBAL unsigned char chw[maxnfonts][256];
  681.   684            GLOBAL char fname[maxnfonts][32];
  682.   685             
  683.   686            /* The LN03 font-denoting numbers 10-19 have to be allocated among the
  684.   687            fonts. The useno array keeps track of which number a font is allowed to
  685.   688            use, -1 if none is currently allocated. The whouses array says which font
  686.   689            is using a number. */ 
  687.   690             
  688.   691            GLOBAL int useno[maxnfonts],whouses[maxfontnos];
  689.   692             
  690.   693            /* Font_name points to strings containing font names, which are created
  691.   694            with malloc as needed. */ 
  692.   695             
  693.   696            GLOBAL char *font_name[MAXTEXFONTS+1]; 
  694.   697             
  695.   698            GLOBAL int maxrmar,maxbmar;
  696.   699             
  697.   700            #define max(x,y) (((x)>(y))?(x):(y))
  698.   701            #define min(x,y) (((x)<(y))?(x):(y))
  699.   702             
  700.   703            /* Make_font_load calls on other procedures to generate the LN03 font load.
  701.   704            */ 
  702.   705             
  703.   706            int make_font_load() {
  704.   707    1           
  705.   708    1           int i,j,jj,k,l,fno,maxfno,chsize;
  706.   709    1           long int totsize;
  707.   710    1           int lnfcnt,txfcnt,the_txf,txf_size,lnfleft;
  708.   711    1           int txford[MAXTEXFONTS];
  709.   712    1           char cnt[3];
  710.   713    1        
  711.   714    1           totsize = 0;
  712.   715    1           chsize = 0;
  713.   716    1           curf = 0;
  714.   717    1           for (i=0; i<maxnfonts; i++) 
  715.   718    1               for (j=0; j<256; j++) chw[i][j] = 0;
  716.  
  717. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 14
  718. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  719.  
  720.   719    1        
  721.   720    1           for (jj=0; jj<MAXTEXFONTS; jj++) txf2lnf[jj] = -1;
  722.   721    1        
  723.   722    1       /* Fill the fname strings with different valid LN03 font names. */ 
  724.   723    1        
  725.   724    1           for (i=0; i<maxnfonts; i++) 
  726.   725    1               strcpy(fname[i],"U000000002SK00GG0001UZZZZ02F000");
  727.   726    1           for (jj=1; jj<maxnfonts; jj++) {
  728.   727    2               sprintf(cnt,"%02d",jj);
  729.   728    2               strncpy(&(fname[jj][5]),cnt,2);
  730.   729    2           }
  731.   730    1        
  732.   731    1       /* The margins are set to values appropriate for American 8 1/2 by 11
  733.   732    1       paper. It is not clear if this needs to be changed for European A4 paper.
  734.   733    1       Not changing it might deprive Europeans of access to the bottom 1.5cm of
  735.   734    1       their paper. */ 
  736.   735    1        
  737.   736    1           maxrmar = 2550;
  738.   737    1           maxbmar = 3300;
  739.   738    1        
  740.   739    1       /* In the following, esc[?27h means "advance the carriage by the character
  741.   740    1       width when you set a character", esc[11h and esc[7 I together mean to
  742.   741    1       interpret all dimensions in escape sequences as pixel units; esc[?52h means
  743.   742    1       our origin of coordinates is the upper left edge of the paper; esc[%dt
  744.   743    1       means the "maximum length" of the paper is maxbmar pixels. */ 
  745.   744    1        
  746.   745    1           fprintf(outfile,"\033c\033[?27h\033[11h\033[7 I\033[?52h\033[%dt\n",
  747.   746    1               maxbmar);
  748.   747    1        
  749.   748    1           for (i=0; i<maxnfonts; i++) useno[i] = -1;
  750.   749    1           for (i=0; i<maxfontnos; i++) whouses[i] = -1;
  751.   750    1           maxfno = -1;
  752.   751    1        
  753.   752    1       /* Write font loading escape sequence onto outf. [[It may be desirable to
  754.   753    1       make this escape sequence clear all dowloaded fonts from RAM.]] */ 
  755.   754    1        
  756.   755    1           fprintf(outfile,"\033P0;1;1y");
  757.   756    1        
  758.   757    1       /* Count how many glyphs each font requires. */
  759.   758    1        
  760.   759    1           for (fno=0; fno<nf; fno++) {
  761.   760    2        
  762.   761    2               txfa[fno] -> nchs = 0;
  763.   762    2               for(i=0; i<256; i++) 
  764.   763    2               if (txfa[fno] -> chu[i] != 0) txfa[fno] -> nchs++;
  765.   764    2        
  766.   765    2           if (txfa[fno] -> nchs > 188)  goto need_empty_slots;
  767.   766    2           chsize += txfa[fno] -> nchs;
  768.   767    2           }
  769.   768    1           printf("\nFont load to contain %d glyphs.",chsize);
  770.   769    1        
  771.  
  772. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 15
  773. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  774.  
  775.   770    1        
  776.   771    1       /* Now we have to allocate TeX fonts to LN03 fonts pairs and perform the
  777.   772    1       actual load. The goal is to use as few slots as possible, where an LN03
  778.   773    1       font pair with <= 94 glyphs is one slot, and a font pair with > 94 but <=
  779.   774    1       188 glyphs is two slots. 
  780.   775    1        
  781.   776    1       As in the LN01 case, the allocation problem seems to be some sort of hard
  782.   777    1       bin packing problem. (Proof of NP-hardness, anyone?) So we use a best fit
  783.   778    1       heuristic: 
  784.   779    1        
  785.   780    1       1.     Find the unassigned largest TeX font. If none, exit, we're done.
  786.   781    1        
  787.   782    1       2.    Allocate an LN03 font pair for that TeX font and put the TeX
  788.   783    1               font into it.
  789.   784    1        
  790.   785    1       3.    Find the largest remaining TeX font that fits in what is left of 
  791.   786    1               that LN03 font pair.
  792.   787    1        
  793.   788    1           3.1. if none exists, go to 1.
  794.   789    1           3.2. if one exists, put it in the font pair and go back to 3.
  795.   790    1        
  796.   791    1       The txford array contains the TeX font numbers in the order that they are
  797.   792    1       assigned. Txfcnt keeps track of how many TeX fonts have been assigned so
  798.   793    1       far. */ 
  799.   794    1        
  800.   795    1           lnfcnt = 0;
  801.   796    1           txfcnt = 0;
  802.   797    1           for (i=0; i<MAXTEXFONTS; i++) txford[i] = -1;
  803.   798    1        
  804.   799    1           while (1) {
  805.   800    2        
  806.   801    2       /* Find largest unassigned TeX font */
  807.   802    2        
  808.   803    2           lnfleft = rightlast-rightfirst+1+leftlast-leftfirst+1;
  809.   804    2           txf_size = -1;
  810.   805    2           for (j = 0; j < MAXTEXFONTS; j++) {
  811.   806    3               if (txfa[j] != 0 && txf2lnf[j] == -1 
  812.   807    3               && txfa[j] -> nchs > txf_size) {
  813.   808    4               txf_size = txfa[j] -> nchs;
  814.   809    4               the_txf = j;
  815.   810    4               }
  816.   811    3           }
  817.   812    2           if (txf_size <= 0)  goto assignment_done;
  818.   813    2           if (lnfcnt > maxnfonts)  goto too_complex;
  819.   814    2           if (txf_size > lnfleft)  goto need_empty_slots;
  820.   815    2        
  821.   816    2       /* Now allocate new LN03 font pair and put the current TeX font into it */ 
  822.   817    2        
  823.   818    2           txf2lnf[the_txf] = lnfcnt;
  824.   819    2           txford[txfcnt] = the_txf;
  825.   820    2           txfcnt++;
  826.  
  827. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 16
  828. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  829.  
  830.   821    2           k = leftfirst-1;
  831.   822    2           for (j = 0; j <= 255; j++) {
  832.   823    3               if (txfa[the_txf] -> chu[j] != 0) {
  833.   824    4               k++;
  834.   825    4               if (k == leftlast+1)  k = rightfirst;
  835.   826    4               lnfleft--;
  836.   827    4               txfa[the_txf] -> chu[j] = k; 
  837.   828    4               }
  838.   829    3           }
  839.   830    2           lastch[lnfcnt] = k;
  840.   831    2        
  841.   832    2       /* Now try to fill the remaining part of the LN03 font pair using other TeX
  842.   833    2       fonts */ 
  843.   834    2        
  844.   835    2           while (1) {
  845.   836    3        
  846.   837    3               txf_size = -1;
  847.   838    3               for (j = 0; j < MAXTEXFONTS; j++) {
  848.   839    4               if (txfa[j] != 0 && txf2lnf[j] == -1
  849.   840    4                   && txfa[j] -> nchs > txf_size 
  850.   841    4                   && txfa[j] -> nchs <= lnfleft) {
  851.   842    5                   txf_size = txfa[j] -> nchs;
  852.   843    5                   the_txf = j;
  853.   844    5               }    
  854.   845    4               }
  855.   846    3               if (txf_size <= 0)  break;
  856.   847    3                   
  857.   848    3               txf2lnf[the_txf] = lnfcnt;
  858.   849    3               txford[txfcnt] = the_txf;
  859.   850    3               txfcnt++;
  860.   851    3               k = lastch[lnfcnt];
  861.   852    3               for (j=0; j<=255; j++) {
  862.   853    4               if (txfa[the_txf] -> chu[j] != 0) {
  863.   854    5                   k++;
  864.   855    5                   lnfleft--;
  865.   856    5                   if (k == leftlast+1) k = rightfirst;
  866.   857    5                   txfa[the_txf] -> chu[j] = k; 
  867.   858    5               }
  868.   859    4               }
  869.   860    3               lastch[lnfcnt] = k;
  870.   861    3           }
  871.   862    2           
  872.   863    2           lnfcnt++;
  873.   864    2           }
  874.   865    1        
  875.   866    1       assignment_done:
  876.   867    1        
  877.   868    1       /* At this point the array txf2lnf is properly initialized, as are lastch
  878.   869    1       and txford. It remains to actually generate the desired font load. This has
  879.   870    1       to be done carefully, since the function add_txf_to_lnf only supports
  880.   871    1       adding glyphs to an LN03 font pair in ascending order of character code. */
  881.  
  882. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 17
  883. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  884.  
  885.   872    1        
  886.   873    1           for (j=0; j<txfcnt; j++) {
  887.   874    2           k = txford[j];
  888.   875    2           if (j != 0 && txf2lnf[k] != txf2lnf[txford[j-1]])  
  889.   876    2               fprintf(outfile,",\n");
  890.   877    2           totsize += add_txf_to_lnf(txf2lnf[k],k);
  891.   878    2           }
  892.   879    1        
  893.   880    1       /* [[At this point we ought to add code that writes a message saying how
  894.   881    1       much font RAM the load will occupy. But there is no documentation for
  895.   882    1       determining that! So, we make the following compromise:]] */ 
  896.   883    1        
  897.   884    1           printf("\n Approximate size of font load: %ld bytes",totsize);
  898.   885    1        
  899.   886    1       /* [[We may want to insert a few \n's in the following to keep the line
  900.   887    1       from getting too long.]] */ 
  901.   888    1        
  902.   889    1           fprintf(outfile,"\n;Dvi2ln3 1 font load\033\\");
  903.   890    1           fprintf(outfile,"\033[1;%ds\033[%dt\033[1;%dr",maxrmar,maxbmar,maxbmar);
  904.   891    1           for (j=0; j <= min(maxfontnos,lnfcnt-1); j++) {
  905.   892    2           useno[j] = j;
  906.   893    2           whouses[j] = j;
  907.   894    2               k = fname[j][16];
  908.   895    2               fname[j][16] = '\0';
  909.   896    2           fprintf(outfile,"\033P1;1%d}%s\033\\",j,fname[j]);
  910.   897    2               fname[j][16] = k;
  911.   898    2           }
  912.   899    1           fprintf(outfile,"\033[10m");
  913.   900    1        
  914.   901    1           return(0);
  915.   902    1        
  916.   903    1       too_complex:
  917.   904    1           printf("\n Can't construct a font load:");
  918.   905    1           printf("\n Dvi file uses too many glyphs from too many different fonts.");
  919.   906    1           return(1);
  920.   907    1        
  921.   908    1       /* [[We need to determine what the real limit is on the number of LN03
  922.   909    1       fonts, and refine the test to detect if it is being exceeded. Fortunately,
  923.   910    1       only a very complex DVI file could exceed the limit.]] */ 
  924.   911    1        
  925.   912    1       need_empty_slots:
  926.   913    1           printf("\nFont %s uses > 188 characters. Can't handle that.",
  927.   914    1               font_name[fno]);
  928.   915    1           return(1);
  929.   916    1        
  930.   917    1       /* [[The error message above should be fixed to specify the magnification
  931.   918    1       of the font also.]] */
  932.   919    1        
  933.   920    1       }
  934.   921             
  935.   922            /* The lines in the LN3 file are limited to lengths of about 100 bytes. We
  936.  
  937. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 18
  938. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  939.  
  940.   923            keep track of how many bytes are written so far in the global lnhp. The
  941.   924            accounting is conservative, so e.g. each pixel position counts as 4 bytes
  942.   925            even though it might be shorter. [[One could easily increase 100 to 200. It
  943.   926            is not clear what problems are provoked by going over, say, 256.]] 
  944.   927             
  945.   928            Vpset keeps track of whether the vertical position needs to be output to
  946.   929            the LN03 file before setting any more characters. Hh_old keeps track of the
  947.   930            horizontal position which LN03 thinks it's at. */ 
  948.   931             
  949.   932            GLOBAL int ln3p,vpset,hh_old;
  950.   933             
  951.   934            #define inc_ln3p(x) ln3p += x; if (ln3p > 100) \
  952.   935                { ln3p = 0; vpset = 0; hh_old = 30000; }
  953.   936             
  954.   937            /* [[In the above macro, hh_old is set to 30000 to mean "a very large
  955.   938            number" (the maximum valid hh for an LN03 is 2550), so as to force the code
  956.   939            below to re-output the true hh. What are the implications of this kludge?
  957.   940            Would it not be more reasonable to have instead an hhset variable?]] */ 
  958.   941             
  959.   942            /* A stack of hvxyzw values is kept; the stack pointer is called s.
  960.   943            [[Again, it would be better to make this stack a linked list.]] */ 
  961.   944             
  962.   945            #define STACKSIZE 100
  963.   946             
  964.   947            GLOBAL long hstack[STACKSIZE], vstack[STACKSIZE], xstack[STACKSIZE], 
  965.   948                ystack[STACKSIZE], zstack[STACKSIZE], wstack[STACKSIZE];
  966.   949            GLOBAL int hhstack[STACKSIZE], vvstack[STACKSIZE];
  967.   950            GLOBAL int s;
  968.   951             
  969.   952            /* DVI files specify distances in units of 2^-16 points. When translating
  970.   953            to a device-specific format, it is necessary to round the DVI distances to
  971.   954            pixel units. This is done by means of the pixel_round macro. 
  972.   955             
  973.   956            However, rather than using this macro in the straightforward way, rounding
  974.   957            is often performed by more elaborate techniques, which we call "Stanford
  975.   958            rules" (after John Le Carre's "Moscow rules"). These rules make use of a
  976.   959            parameter MAX_DRIFT, which is roughly the maximum number of pixels that
  977.   960            things are allowed to deviate from straightforward rounding. */ 
  978.   961             
  979.   962            #define pixel_round(x) ((int) ((x<0) ? \
  980.   963                (conv*(x)-0.5) : (conv*(x)+0.5)))
  981.   964                
  982.   965            #define MAX_DRIFT 2
  983.   966             
  984.   967            /* Pass2 reads the dvi file and interprets the commands in it, usually by
  985.   968            calling other routines. The interpretation generally consists of writing
  986.   969            something into the ln3 file, updating the current fonts and positions, and
  987.   970            possibly updating the stack. */ 
  988.   971             
  989.   972            int pass2()
  990.   973            {
  991.  
  992. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 19
  993. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  994.  
  995.   974    1           int i,j;
  996.   975    1           long int p;
  997.   976    1           unsigned int k;
  998.   977    1           
  999.   978    1           if (read_preamble() != 0) {
  1000.   979    2               printf(bad_DVI_message);
  1001.   980    2               return(1);
  1002.   981    2           }
  1003.   982    1        
  1004.   983    1           curf = 0;
  1005.   984    1           ln3p = 0;
  1006.   985    1           s = 0;
  1007.   986    1           vpset = 0;
  1008.   987    1           hh_old = 30000;
  1009.   988    1        
  1010.   989    1       /* Skip pages until the desired starting page is reached. A nonzero value
  1011.   990    1       is returned if the starting page is never encountered. */ 
  1012.   991    1        
  1013.   992    1           if (skip_pages() != 0) return(0); 
  1014.   993    1        
  1015.   994    1           for (;;) {
  1016.   995    2               if feof(dvifile) { 
  1017.   996    3                   printf(bad_DVI_message);
  1018.   997    3                   return(1); }
  1019.   998    2               k = getc(dvifile);
  1020.   999    2               if (k == post) return(0);
  1021.  1000    2               if (k >= undefined_command) {
  1022.  1001    3                   printf(bad_DVI_message);
  1023.  1002    3               return(1); }
  1024.  1003    2               
  1025.  1004    2           p = first_par(k);    
  1026.  1005    2        
  1027.  1006    2       /* If the opcode is an "implicit parameter" opcode, either set_char_n and
  1028.  1007    2       fnt_num_n, we change it to an explicit parameter opcode to make the case
  1029.  1008    2       jumps more reasonable. */ 
  1030.  1009    2        
  1031.  1010    2               if (k >= set_char_0 && k < set_char_0+128) k = set1;
  1032.  1011    2               if (k >= fnt_num_0 && k < fnt_num_0+64) k = fnt1;
  1033.  1012    2        
  1034.  1013    2               j = do_command(k,p);
  1035.  1014    2               if (j == 2) return(0); /* done with the required number of pages */
  1036.  1015    2               else if (j == 1) return(1); /* error encountered, stop */
  1037.  1016    2        
  1038.  1017    2           }
  1039.  1018    1       }
  1040.  1019             
  1041.  1020            /* Read from the DVI file until the starting page condition is met. Return
  1042.  1021            1 if something goes wrong, or if the DVI file comes to an end. This 
  1043.  1022            function is copied quite closely from DVItype. */ 
  1044.  1023             
  1045.  1024            int skip_pages() {
  1046.  
  1047. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 20
  1048. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  1049.  
  1050.  1025    1        
  1051.  1026    1           unsigned int k;
  1052.  1027    1           int i;
  1053.  1028    1           long p,first_page;
  1054.  1029    1           char startp;
  1055.  1030    1           
  1056.  1031    1           for (;;) {
  1057.  1032    2           if (feof(dvifile)) return(1);
  1058.  1033    2           k = getc(dvifile);
  1059.  1034    2           if (k == post) return(1);
  1060.  1035    2           p = first_par(k);
  1061.  1036    2           if (k >= set_char_0 && k < set_char_0+128) k = set1;
  1062.  1037    2           if (k >= fnt_num_0 && k < fnt_num_0+64) k = fnt1;
  1063.  1038    2        
  1064.  1039    2           switch (k) {
  1065.  1040    3               case bop:
  1066.  1041    3               startp = 1;
  1067.  1042    3               for (i=0; i<10; i++) {
  1068.  1043    4                   four_bytes;
  1069.  1044    4                       if (i == 0) first_page = lcx.l;
  1070.  1045    4                   if (i < how_many_counts && use_count[i] &&
  1071.  1046    4                       lcx.l != start_page[i]) startp = 0;
  1072.  1047    4                   }
  1073.  1048    3                   four_bytes;
  1074.  1049    3               if (startp != 0) { 
  1075.  1050    4                   v = 0; vv = 0; h = 0; hh = 0;
  1076.  1051    4                       printf("\n [%ld]",first_page);
  1077.  1052    4                       num_pages = 1; return(0); }
  1078.  1053    3                   break;
  1079.  1054    3                   case set_rule:
  1080.  1055    3                   case put_rule:
  1081.  1056    3                   four_bytes;
  1082.  1057    3                   break;
  1083.  1058    3               four_cases(fnt_def1)
  1084.  1059    3                   i = define_font(p);
  1085.  1060    3                   if (i != 0) return(1);
  1086.  1061    3                   break;
  1087.  1062    3               four_cases(xxx1)
  1088.  1063    3                   for (; p>0; p--) getc(dvifile);
  1089.  1064    3               break;
  1090.  1065    3                   default:
  1091.  1066    3                   break;
  1092.  1067    3           }
  1093.  1068    2           }
  1094.  1069    1           return(0);
  1095.  1070    1       }
  1096.  1071             
  1097.  1072            /* Do_command performs the DVI command of code k, assuming the "first
  1098.  1073            parameter" is p. It is assumed that k is not one of set_char0 through
  1099.  1074            set_char127. */ 
  1100.  1075             
  1101.  
  1102. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 21
  1103. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  1104.  
  1105.  1076            int do_command(k,p)
  1106.  1077            int k;
  1107.  1078            long p;
  1108.  1079            {
  1109.  1080    1           int i,j,l,lnf;
  1110.  1081    1        
  1111.  1082    1           switch (k) {
  1112.  1083    2           four_cases(fnt_def1)
  1113.  1084    2               define_font_pass2();
  1114.  1085    2               break;
  1115.  1086    2        
  1116.  1087    2       /* [[In processing the put and set DVI commands, no check is made that the
  1117.  1088    2       character being set actually exists in the font. This can lead to messy
  1118.  1089    2       errors, like access violations or garbage values when one tries to find
  1119.  1090    2       that character's width. Neither is any check made that the horizontal and
  1120.  1091    2       vertical positions fall within the page.]] */ 
  1121.  1092    2        
  1122.  1093    2           four_cases(put1)
  1123.  1094    2           four_cases(set1)
  1124.  1095    2                   if (!vpset) {
  1125.  1096    3                   fprintf(outfile,"\n\033[%dd\033[%d`",vv+voff,hh+hoff);
  1126.  1097    3                   ln3p = 16;
  1127.  1098    3                   vpset = 1;
  1128.  1099    3                   hh_old = hh;
  1129.  1100    3                   }
  1130.  1101    2                   if (hh_old != hh) {
  1131.  1102    3                   if (hh > hh_old) fprintf(outfile,"\033[%da",hh-hh_old);
  1132.  1103    3                   else fprintf(outfile,"\033[%d`",hh+hoff);
  1133.  1104    3                   ln3p += 7;
  1134.  1105    3                   }
  1135.  1106    2                   putc(txfa[curf] -> chu[p],outfile);
  1136.  1107    2                   inc_ln3p(1);
  1137.  1108    2               if (k >= put1) {
  1138.  1109    3                       hh_old = hh;
  1139.  1110    3               break;
  1140.  1111    3               }
  1141.  1112    2               h += font_width[curf][p];
  1142.  1113    2        
  1143.  1114    2       /* In rounding h to generate the pixel-position hh, Stanford rules (see
  1144.  1115    2       above) come into play. We set the new hh (horizontal position in pixels) to
  1145.  1116    2       the value obtained by adding the pixel width of the character being set to
  1146.  1117    2       the current position. We then correct this value so that it does not exceed
  1147.  1118    2       the rounded version of the true position by more than MAX_DRIFT pixels.
  1148.  1119    2        
  1149.  1120    2       Note that if we did not apply Stanford rules here, or equivalently if we
  1150.  1121    2       set MAX_DRIFT to zero, many more set-X-position commands would appear in
  1151.  1122    2       the output. */
  1152.  1123    2        
  1153.  1124    2               hh += chw[txf2lnf[curf]][txfa[curf] -> chu[p]];
  1154.  1125    2                   hh_old = hh;
  1155.  1126    2               l = pixel_round(h);
  1156.  
  1157. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 22
  1158. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  1159.  
  1160.  1127    2               if (hh-l > MAX_DRIFT) hh = l+MAX_DRIFT;
  1161.  1128    2               else if (l-hh > MAX_DRIFT) hh = l-MAX_DRIFT;
  1162.  1129    2               break;
  1163.  1130    2        
  1164.  1131    2           four_cases(fnt1)
  1165.  1132    2               set_curf(p);
  1166.  1133    2               lnf = txf2lnf[curf];
  1167.  1134    2               if (useno[lnf] == -1) {
  1168.  1135    3               useno[whouses[maxfontnos]] = -1;
  1169.  1136    3               useno[lnf] = maxfontnos;
  1170.  1137    3               whouses[maxfontnos] = lnf;
  1171.  1138    3               fprintf(outfile,"\033P1;1%d}%16s\033\\",maxfontnos,
  1172.  1139    3                       fname[lnf]);
  1173.  1140    3               inc_ln3p(26);
  1174.  1141    3               }
  1175.  1142    2               fprintf(outfile,"\033[1%dm",useno[lnf]);
  1176.  1143    2               inc_ln3p(5);
  1177.  1144    2               break;
  1178.  1145    2        
  1179.  1146    2           case set_rule:
  1180.  1147    2           case put_rule: 
  1181.  1148    2        
  1182.  1149    2       /* When converting rule dimensions to pixel dimensions, we do not follow
  1183.  1150    2       Stanford rules. Rather, we just round the true positions to obtain the
  1184.  1151    2       pixel positions. This avoids unsightly gaps between rules. [[It should not
  1185.  1152    2       cause much of a problem with typical rule applications (ruled tables,
  1186.  1153    2       fraction bars)...but perhaps with large delimiters there might be some
  1187.  1154    2       difficulty. This needs more thought...]] */ 
  1188.  1155    2        
  1189.  1156    2               four_bytes; 
  1190.  1157    2               if (p >= 0 && lcx.l >= 0) 
  1191.  1158    2               do_rule(pixel_round(h),
  1192.  1159    2                   pixel_round(v-p),pixel_round(h+lcx.l),
  1193.  1160    2                   pixel_round(v));
  1194.  1161    2               if (k == set_rule) {
  1195.  1162    3                   h += lcx.l;
  1196.  1163    3               hh = pixel_round(h);
  1197.  1164    3               }
  1198.  1165    2               break;
  1199.  1166    2        
  1200.  1167    2            case push:
  1201.  1168    2               s++;
  1202.  1169    2               if (s == STACKSIZE) {
  1203.  1170    3               printf("\n Stack too deep for Dvi2ln3");
  1204.  1171    3               return(1);
  1205.  1172    3               }
  1206.  1173    2               xstack[s] = x;
  1207.  1174    2               ystack[s] = y;
  1208.  1175    2               vstack[s] = v;
  1209.  1176    2               hstack[s] = h;
  1210.  1177    2               vvstack[s] = vv;
  1211.  
  1212. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 23
  1213. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  1214.  
  1215.  1178    2               hhstack[s] = hh;
  1216.  1179    2               wstack[s] = w;
  1217.  1180    2               zstack[s] = z;
  1218.  1181    2               break;
  1219.  1182    2        
  1220.  1183    2           case pop:
  1221.  1184    2               if (s == 0) {            
  1222.  1185    3               printf(bad_DVI_message); 
  1223.  1186    3               return(1); 
  1224.  1187    3               }
  1225.  1188    2                   if (vv != vvstack[s]) vpset = 0;
  1226.  1189    2               x = xstack[s]; 
  1227.  1190    2               y = ystack[s];    
  1228.  1191    2               v = vstack[s]; 
  1229.  1192    2               h = hstack[s];    
  1230.  1193    2               vv = vvstack[s]; 
  1231.  1194    2               hh = hhstack[s];    
  1232.  1195    2               w = wstack[s]; 
  1233.  1196    2               z = zstack[s];
  1234.  1197    2               s--; 
  1235.  1198    2               break; 
  1236.  1199    2        
  1237.  1200    2       /* Right now there are no \special's defined, so when we get a \special, we
  1238.  1201    2       just skip over it. */ 
  1239.  1202    2        
  1240.  1203    2           four_cases(xxx1)
  1241.  1204    2               for (; p != 0; p--) getc(dvifile);
  1242.  1205    2               break;
  1243.  1206    2        
  1244.  1207    2           case bop:
  1245.  1208    2        
  1246.  1209    2       /* If we've done the required number of pages, we'll skip the rest of the
  1247.  1210    2       DVI file. If not, type the first parameter of bop on the user's terminal
  1248.  1211    2       the way TeX does, to give an indication of progress. */ 
  1249.  1212    2        
  1250.  1213    2                   if (num_pages == max_pages) return(2);
  1251.  1214    2               v = 0; vv = 0; h = 0; hh = 0;
  1252.  1215    2                   vpset = 0; hh_old = 100000;
  1253.  1216    2                   four_bytes;
  1254.  1217    2               if (num_pages%12 == 0) printf("\n");
  1255.  1218    2               printf(" [%ld]",lcx.ul);
  1256.  1219    2                   num_pages++;
  1257.  1220    2               for (i = 0; i<40; i++) getc(dvifile); 
  1258.  1221    2               break;
  1259.  1222    2        
  1260.  1223    2           case eop:
  1261.  1224    2               fprintf(outfile,"\n\f");
  1262.  1225    2               ln3p = 0;
  1263.  1226    2               break;
  1264.  1227    2        
  1265.  1228    2       /* Now we have to consider the cases for pure motion. */
  1266.  
  1267. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 24
  1268. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  1269.  
  1270.  1229    2        
  1271.  1230    2           four_cases(right1)
  1272.  1231    2               set_h(h+p);
  1273.  1232    2               break;
  1274.  1233    2           four_cases(x1)
  1275.  1234    2               x = p;
  1276.  1235    2           case x0:
  1277.  1236    2               set_h(h+x);
  1278.  1237    2               break;
  1279.  1238    2           four_cases(y1)
  1280.  1239    2               y = p;
  1281.  1240    2           case y0:
  1282.  1241    2               set_v(v+y);
  1283.  1242    2               break;
  1284.  1243    2           four_cases(w1)
  1285.  1244    2               w = p;
  1286.  1245    2           case w0:
  1287.  1246    2               set_h(h+w);
  1288.  1247    2               break;
  1289.  1248    2           four_cases(z1)
  1290.  1249    2               z = p;
  1291.  1250    2           case z0:
  1292.  1251    2               set_v(v+z);
  1293.  1252    2               break;
  1294.  1253    2           four_cases(down1)
  1295.  1254    2               set_v(v+p);
  1296.  1255    2               break;
  1297.  1256    2        
  1298.  1257    2           }    
  1299.  1258    1           return(0);
  1300.  1259    1       }
  1301.  1260             
  1302.  1261            /* Set_curf sets the current font to external number p. Note that the
  1303.  1262            current font is maintained as an internal font number. */ 
  1304.  1263             
  1305.  1264            int set_curf(p)
  1306.  1265            int p;
  1307.  1266            {
  1308.  1267    1           to_ext[nf] = p;
  1309.  1268    1           curf = 0;
  1310.  1269    1           while (to_ext[curf] != p) { curf++; }    
  1311.  1270    1       }
  1312.  1271             
  1313.  1272            /* Define_font processes a font definition from the DVI file. The TFM file
  1314.  1273            for the font is read at this point from the directory TEX$FONTS. */ 
  1315.  1274             
  1316.  1275            int define_font(e)
  1317.  1276            int e;
  1318.  1277            {
  1319.  1278    1           int i;
  1320.  1279    1           unsigned char p,n;
  1321.  
  1322. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 25
  1323. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  1324.  
  1325.  1280    1           if (e == MAXTEXFONTS) { printf("\n Too many fonts for Dvi2ln3");
  1326.  1281    2               return(1); }
  1327.  1282    1           txfa[nf] = malloc(sizeof(struct txf));
  1328.  1283    1           to_ext[nf] = e;
  1329.  1284    1           four_bytes;
  1330.  1285    1           four_bytes;
  1331.  1286    1           txfa[nf] -> scaled_size = lcx.l;
  1332.  1287    1           four_bytes;
  1333.  1288    1           txfa[nf] -> design_size = lcx.l;
  1334.  1289    1           for (i=0; i<256; i++) txfa[nf] -> chu[i] = '\0';
  1335.  1290    1           p = getc(dvifile); n = getc(dvifile);
  1336.  1291    1           font_name[nf] = malloc(p+n+1);
  1337.  1292    1           for (i=0; i<p+n; i++) { font_name[nf][i] = getc(dvifile); }
  1338.  1293    1           font_name[nf][p+n] = '\0';
  1339.  1294    1        
  1340.  1295    1           if (txfa[nf] -> scaled_size <= 0 || txfa[nf] -> scaled_size >=
  1341.  1296    1               8*8*8*8*8*8*8*8*8) {
  1342.  1297    2               printf("\n Font %s has a bad scaled size",font_name[nf]);
  1343.  1298    2               return(1);
  1344.  1299    2           }
  1345.  1300    1           if (txfa[nf] -> design_size <= 0 || txfa[nf] -> design_size >= 
  1346.  1301    1               8*8*8*8*8*8*8*8*8) {
  1347.  1302    2               printf("\n Font %s has a bad design size",font_name[nf]);
  1348.  1303    2               return(1);
  1349.  1304    2           }
  1350.  1305    1        
  1351.  1306    1       /* We follow DVItype and compute for each font a "space" parameter which is
  1352.  1307    1       one-sixth of the scaled design size. This parameter is used in rounding the
  1353.  1308    1       horizontal position to pixels according to "Stanford rules." See the
  1354.  1309    1       function set_h below. */ 
  1355.  1310    1        
  1356.  1311    1           txfa[nf] -> space = txfa[nf] -> scaled_size/6;     
  1357.  1312    1        
  1358.  1313    1           i = read_tfm_file();
  1359.  1314    1           if (i != 0) return(i);
  1360.  1315    1           nf++;
  1361.  1316    1           return(0); 
  1362.  1317    1        
  1363.  1318    1       }
  1364.  1319             
  1365.  1320            /* TFM files, like the DVI file, are read with getc, foolish as that may
  1366.  1321            seem. We use the same overlays that are used for merging DVI bytes into
  1367.  1322            longwords. However, since the TFM file consists of longwords, only
  1368.  1323            tfm_longword is need. [[This is also VAX dependent. It would not be
  1369.  1324            possible to use stdio's longword reading function getw here, because the
  1370.  1325            bytes have to be reversed.]] */ 
  1371.  1326             
  1372.  1327            #define tfm_longword { lcx.uc[3] = getc(tfmfile); \
  1373.  1328                lcx.uc[2] = getc(tfmfile); lcx.uc[1] = getc(tfmfile); \
  1374.  1329                lcx.uc[0] = getc(tfmfile); }
  1375.  1330             
  1376.  
  1377. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 26
  1378. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  1379.  
  1380.  1331            /* Read_tfm_file obtains the character widths from the TFM file
  1381.  1332            corresponding to font nf. */ 
  1382.  1333             
  1383.  1334            int read_tfm_file() {
  1384.  1335    1        
  1385.  1336    1           int i,lh,nw;
  1386.  1337    1           int info[256];
  1387.  1338    1           long z,alpha,beta;
  1388.  1339    1           long width[256];
  1389.  1340    1        
  1390.  1341    1           open_tfm_file();
  1391.  1342    1           if (tfmfile == NULL) {
  1392.  1343    2               printf("\n Can't open TFM file for font %s",font_name[nf]);
  1393.  1344    2               return(1); }
  1394.  1345    1        
  1395.  1346    1       /* The TFM format is described in some issue of the TUGBoat (TeX users'
  1396.  1347    1       group newsletter), and in the comments to the program TFtoPL. Here we
  1397.  1348    1       summarize those aspects of TFM format that are relevant to the task of
  1398.  1349    1       extracting the widths of the characters. 
  1399.  1350    1        
  1400.  1351    1       The first 24 bytes of a TFM file contain twelve 16-bit integers that give
  1401.  1352    1       the lengths of the various subsequent portions of the file. The ones
  1402.  1353    1       relevant to our purposes are LH, length of the header data, BC, the
  1403.  1354    1       smallest character code in the font, EC, the largest character code in the
  1404.  1355    1       font, and NW, number of words in the width table. So, we read those right
  1405.  1356    1       now, and then skip over the remainder, and then over a set of LH longwords
  1406.  1357    1       called the "header." */ 
  1407.  1358    1        
  1408.  1359    1           tfm_longword; 
  1409.  1360    1           lh = 256*lcx.uc[1] + lcx.uc[0];
  1410.  1361    1           tfm_longword;
  1411.  1362    1           txfa[nf] -> bc = 256*lcx.uc[3] + lcx.uc[2];
  1412.  1363    1           txfa[nf] -> ec = 256*lcx.uc[1] + lcx.uc[0];
  1413.  1364    1           tfm_longword;
  1414.  1365    1           nw = 256*lcx.uc[3] + lcx.uc[2];
  1415.  1366    1           if (txfa[nf] -> bc > 255 || txfa[nf] -> ec > 255 ||
  1416.  1367    1               txfa[nf] -> bc > txfa[nf] -> ec || nw > 256) {
  1417.  1368    2               printf("\n Bad TFM file for font %s",font_name[nf]);
  1418.  1369    2               return(1);
  1419.  1370    2           }        
  1420.  1371    1        
  1421.  1372    1           for(i=0; i<lh+3; i++) tfm_longword;
  1422.  1373    1        
  1423.  1374    1       /* After the header, there are two arrays in the TFM file that interest us.
  1424.  1375    1       The first, INFO, is EC-BC+1 longwords long and contains pointers to the
  1425.  1376    1       second, WIDTH, which is NW longwords long. For each character i, the width
  1426.  1377    1       of i is WIDTH[INFO[i-BC]]. We read these arrays into memory. */ 
  1427.  1378    1        
  1428.  1379    1           for(i=0; i<txfa[nf] -> ec-txfa[nf] -> bc+1; i++) {
  1429.  1380    2               tfm_longword;
  1430.  1381    2               if (lcx.uc[3] >= nw) {
  1431.  
  1432. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 27
  1433. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  1434.  
  1435.  1382    3               printf("\n Bad TFM file for font %s",font_name[nf]);
  1436.  1383    3               return(1);
  1437.  1384    3           }        
  1438.  1385    2               info[i] = lcx.uc[3];
  1439.  1386    2           }
  1440.  1387    1        
  1441.  1388    1       /* The widths are stored in a rather strange format known as a "fix-word."
  1442.  1389    1       A nonnegative width is expressed in "fix-word" format by expressing it in
  1443.  1390    1       units of 2^-20 times the design size. A negative width is expressed in
  1444.  1391    1       "fix-word" format by expressing its negative in those units, and then
  1445.  1392    1       changing the most significant byte to 255. 
  1446.  1393    1        
  1447.  1394    1       One needs to convert these widths into DVI units, multiplying by the scaled
  1448.  1395    1       design size according to a certain arcane algorithm. The algorithm is
  1449.  1396    1       copied from DVItype, to which we refer the reader for an explanation. */ 
  1450.  1397    1        
  1451.  1398    1           z = txfa[nf] -> scaled_size;
  1452.  1399    1           alpha = 16*z; beta = 16;
  1453.  1400    1           while (z >= 4*(8*8*8*8*8*8*8)) { z = z/2; beta = beta/2; }
  1454.  1401    1           for(i=0; i<nw; i++) {
  1455.  1402    2               tfm_longword;
  1456.  1403    2               width[i] = ( ( (lcx.uc[0]*z)/256 + lcx.uc[1]*z )/256  + 
  1457.  1404    2                   lcx.uc[2]*z)/beta;
  1458.  1405    2               if (lcx.uc[3] == 255) width[i] -= alpha;
  1459.  1406    2           }
  1460.  1407    1        
  1461.  1408    1           fclose(tfmfile);
  1462.  1409    1        
  1463.  1410    1       /* Using these two arrays, we now compute the widths of the characters in
  1464.  1411    1       the fonts and place them into two malloc'ed arrays, one for the widths in
  1465.  1412    1       DVI units, one for the width in pixel units. */ 
  1466.  1413    1        
  1467.  1414    1           font_width[nf] = malloc(4*(txfa[nf] -> ec+1));
  1468.  1415    1           
  1469.  1416    1           for (i=0; i<txfa[nf] -> bc; i++) font_width[nf][i] = 0;
  1470.  1417    1           for (i=txfa[nf] -> bc; i <= txfa[nf] -> ec; i++) 
  1471.  1418    1           font_width[nf][i] = width[info[i-txfa[nf] -> bc]];
  1472.  1419    1           return(0);
  1473.  1420    1       }
  1474.  1421             
  1475.  1422            /* Open_tfm_file finds and opens the tfm file corresponding to a font nf.
  1476.  1423            The global file variable tfmfile is used to hold the file pointer. [[This
  1477.  1424            function will not work if the TFM file lies over the net on a VMS V3.x
  1478.  1425            host, because C file opens do not work in such circumstances. The problem
  1479.  1426            can be ignored, because eventually there should be no VMS V3.x hosts
  1480.  1427            left.]] */ 
  1481.  1428             
  1482.  1429            int open_tfm_file () {
  1483.  1430    1        
  1484.  1431    1           int jext,jnam;
  1485.  1432    1           char filespec[FILESPECLEN];
  1486.  
  1487. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 28
  1488. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  1489.  
  1490.  1433    1        
  1491.  1434    1           find_VMS_filename(font_name[nf],&jnam,&jext);
  1492.  1435    1           filespec[0] = '\0';
  1493.  1436    1        
  1494.  1437    1       /* If there is no directory part, fill in using the logical tex$fonts */ 
  1495.  1438    1        
  1496.  1439    1           if (jnam == 0) strcpy(filespec,"tex$fonts:");
  1497.  1440    1           strcat(filespec,font_name[nf]);
  1498.  1441    1        
  1499.  1442    1       /* if there is no extension, add the extension ".tfm" */
  1500.  1443    1        
  1501.  1444    1           if (font_name[nf][jext] == '\0') strcat(filespec,".tfm");
  1502.  1445    1           tfmfile = fopen(filespec,"r");
  1503.  1446    1        
  1504.  1447    1       }
  1505.  1448             
  1506.  1449            /* Define_font_pass2 skips a font definition from the DVI file. */ 
  1507.  1450             
  1508.  1451            int define_font_pass2()
  1509.  1452            {
  1510.  1453    1           unsigned char p,n;
  1511.  1454    1           int i;
  1512.  1455    1           four_bytes;
  1513.  1456    1           four_bytes;
  1514.  1457    1           four_bytes;
  1515.  1458    1           p = getc(dvifile); n = getc(dvifile);
  1516.  1459    1           for (i=0; i<p+n; i++) getc(dvifile);
  1517.  1460    1       }
  1518.  1461             
  1519.  1462            /* Do_rule writes into the ln3 file the escape sequence corresponding
  1520.  1463            to a rule. */
  1521.  1464             
  1522.  1465            int do_rule(xx0,yy0,xx1,yy1) 
  1523.  1466            int xx0,yy0,xx1,yy1;
  1524.  1467            {
  1525.  1468    1           int j;
  1526.  1469    1        
  1527.  1470    1           xx0 = min(xx0+hoff,maxrmar);
  1528.  1471    1           xx1 = min(xx1+hoff,maxrmar);
  1529.  1472    1           xx0 = max(xx0,0);
  1530.  1473    1           xx1 = max(xx1,0);
  1531.  1474    1           yy0 = min(yy0+voff,maxbmar);
  1532.  1475    1           yy1 = min(yy1+voff,maxbmar);
  1533.  1476    1           yy0 = max(yy0,0);
  1534.  1477    1           yy1 = max(yy1,0);
  1535.  1478    1           if (xx0 > xx1) { j = xx0; xx0 = xx1; xx1 = j; }
  1536.  1479    1           if (yy0 > yy1) { j = yy0; yy0 = yy1; yy1 = j; }
  1537.  1480    1                   
  1538.  1481    1           if ((yy1 != yy0 && xx1 != xx0)) {
  1539.  1482    2           fprintf(outfile,"\033[1;%d;%d;%d;%d!|",
  1540.  1483    2               xx0,yy0,yy1-yy0,xx1-xx0);
  1541.  
  1542. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 29
  1543. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  1544.  
  1545.  1484    2           inc_ln3p(25);
  1546.  1485    2           }
  1547.  1486    1       }
  1548.  1487             
  1549.  1488            /* Set_v is called to execute vertical-position-altering commands, other
  1550.  1489            than pops. It modifies v and vv, and outputs the vertical position to the
  1551.  1490            LN3 file. We don't follow Stanford rules here. They sometimes set the
  1552.  1491            vertical position in pixels vv to something other than the rounded value of
  1553.  1492            v. Not following Stanford rules implies, for example, that the relative
  1554.  1493            vertical positions of an accent and its accentee may differ by one pixel
  1555.  1494            according to how the baseline of the accentee gets rounded. [[This should
  1556.  1495            perhaps be fixed.]] */ 
  1557.  1496             
  1558.  1497            int set_v(v1)
  1559.  1498            int v1;
  1560.  1499            {
  1561.  1500    1           int l;
  1562.  1501    1        
  1563.  1502    1           l = pixel_round(v1);
  1564.  1503    1           v = v1;
  1565.  1504    1           vv = l;
  1566.  1505    1           vpset = 0;
  1567.  1506    1       }    
  1568.  1507             
  1569.  1508            /* Set_h is called whenever a DVI command is encountered that alters the
  1570.  1509            horizonal position, other than a set_char, set_rule or pop. It sets h to
  1571.  1510            the new value, and alters hh according to Stanford rules, printing the new
  1572.  1511            hh in the LN3 file. */ 
  1573.  1512             
  1574.  1513            int set_h(new_h)
  1575.  1514            int new_h;   
  1576.  1515            {
  1577.  1516    1           int l,old_hh;
  1578.  1517    1        
  1579.  1518    1           old_hh = hh;
  1580.  1519    1           l = pixel_round(new_h);
  1581.  1520    1           if (txfa[curf] == 0 || new_h-h >= txfa[curf] -> space
  1582.  1521    1               || new_h-h <= -4*txfa[curf] -> space) hh = l;
  1583.  1522    1           else {
  1584.  1523    2               hh += pixel_round(new_h-h);
  1585.  1524    2               if (hh-l > MAX_DRIFT) hh = l+MAX_DRIFT;
  1586.  1525    2               else if (hh-l < -MAX_DRIFT) hh = l-MAX_DRIFT;
  1587.  1526    2           }
  1588.  1527    1           h = new_h;
  1589.  1528    1           return(0);
  1590.  1529    1       }
  1591.  
  1592.  
  1593.  
  1594. Command Line
  1595. ------------
  1596.  
  1597. DVI2LN3                                                         14-OCT-1985 13:19:13    VAX C      V2.0-003                 Page 30
  1598. V1.0                                                            14-OCT-1985 13:19:01    USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1)
  1599.  
  1600.  
  1601. CC/DEB/LIS DVI2LN3
  1602.  
  1603.